package Client;

import java.io.IOException;
import java.net.UnknownHostException;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.Vector;

import javax.sql.rowset.spi.SyncResolver;

import common.BufferIO;
import common.ComandParser;
import common.Ranking;
import common.ServerInterface;
import common.TurnInterface;
import common.UserMap;
import common.UserMap.BoxType;
import common.exception.*;



/**
 * La classe si occupa di fornire un supporto per la connessione tra client-e server
 * Implementa ServerInterface per l'utilizzo da parte del client.
 * Utilizza un BufferIO per la comunicazione Client-Server.
 * 
 * @author Jacopo Ferrigno
 *
 */


/*JAK non sono sicuro che sia tu a doverlo fare, ma ricordo che serve
 * un notifyTurn che vada a dire alla logica del client che è il suo 
 * turno di gioco*/

public class SocketServer extends Thread implements ServerInterface, TurnInterface{

	//Variabili di connessione
	private BufferIO bufferIO;
	private String host="localhost";
	private int port=2000;
	//Variabili per sapere se e' cambiato il turno
	private String playerName="";
	private Boolean isChanged=false;
	//Timer
	
	//Comandi e opzioni corrispondenti
	private String [] comandList={"","creaUtente","login","creaRazza","accessoPartita","uscitaPartita","listaGiocatori","classifica","logout","mappaGenerale","listaDinosauri","vistaLocale","statoDinosauro","muoviDinosauro","cresciDinosauro","deponiUovo","confermaTurno","passaTurno"};
	private String [] optionList={"","token","idDino","user","pass","nome","tipo","dest"};

	//REGEX	
	private String [] patternsServer={"@(\\w{2,}),?\\w",
			",(\\w+)+",
			"\\{(\\w+),(\\w+),(\\d+),([s|n])\\}",
			"(\\w+),(\\w+),(c|e),\\{(\\w+),(\\w+)\\},(\\w+),?(\\d+)?,?(\\d+)?",
			"(v|p)",
			"\\{(\\d+),(\\d+)\\}",
			"\\[(\\w)\\]",	
			"\\[([atn]{0,1})|([vdc]),(\\d+)\\]",
			",(\\w+)+"};
	/*Lista di regex con il loro utilizzo, messaggi server.Se non sai cosa stai facendo, non toccare!
	 * [0], nomecomando, senza la @
	 * [1], lista giocatori,gruppi 1
	 * [1], login, gruppi 1
	 * [2], classifica, gruppi 1,2,3,4
	 * [3], statoDinosauro, gruppi 1,2,3,4,5,6,[7,8]
	 * [4], combattimento,gruppi 1
	 * [5], mappaGenerale,gruppi 1,2, estrae righe,colonne	 
	 * [6], mappaGenerale,gruppi 1, etrae il valore delle caselle;
	 * [5], vistaLocale, gruppi 1,2, estrae Xinizio,Xfine, righe,colonne
	 * [7], vistaLocale, gruppi 1,etrae il valore delle caselle; check null
	 * [8], listaDinosauri, gruppi 1
	 * [8], deponiUovo, gruppo 1
	 * [8], cambioTurno,gruppo 1
	 */
	//private String [] patternsClient={"\\w{2,}=(\\w+),\\w{2,}=(\\w+)","\\w{2,}=(\\w+),\\w{2,}=(\\w+),\\w{2,}=(c|e)",",(\\w+)+",	"\\w{2,}=(\\w+),\\w{2,}=(\\w+),\\w{2,}=\\{(\\w+),(\\w+)\\}"};
	/*Lista di regex con il loro utilizzo, messaggi client
	 * [0], creautente, gruppi 1,2
	 * [0], login,gruppi 1,2
	 * [0], statoDinosauro, gruppi 1,2
	 * [0], cresciDinosauro, gruppi 1,2
	 * [0], vistaLocale, gruppi 1,2
	 * [0], deponiUovo, gruppi 1,2
	 * [1], crearazza, gruppi 1,2,3
	 * [2], accessoPartita, gruppi 1
	 * [2], uscitaPartita, gruppi 1
	 * [2], listaGiocatori, gruppi 1
	 * [2], classifica, gruppi 1
	 * [2], logout, gruppi 1
	 * [2], mappaGenerale, gruppi 1
	 * [2], listaDinosauri, gruppi 1
	 * [2], confermaTurno, gruppi 1
	 * [2], passaTurno, gruppi 1
	 */
	
	/**
	 * Crea un SocketServer che si connette in loopback sulla porta di default(2000)
	 * @throws IOException nel caso sorga qualche problema nella creazione del BufferIO
	 * @throws UnknownHostException nel caso sorga qualche problema nella risoluzione dell'host da raggiungere
	 * 
	 * 
	 */
	
	
 	public SocketServer() throws UnknownHostException, IOException{

 		super("SocketServer");
 		this.bufferIO=new BufferIO(this.host, this.port);
 		this.bufferIO.start();
 		this.start();
 		
 		
		
	}
	
	/**
	 * Crea un socketServer che si connette al host passato come parametro sulla porta di default(2000)
	 * 
	 * @param host indirizzo  ip del server da raggiungere
	 * 
	 * @throws IOException nel caso sorga qualche problema nella creazione del BufferIO
	 * @throws UnknownHostException nel caso sorga qualche problema nella risoluzione dell'host da raggiungere
	 */
	
	public SocketServer(String host) throws UnknownHostException, IOException{
		
		super("SocketServer");
		this.host=host;
				
		this.bufferIO=new BufferIO(this.host, this.port);
		this.bufferIO.start();
		this.start();
		
	}
	
	/**
	 * Crea un socketServer che si connette al host passato come parametro sulla porta specificata 
	 * 
	 * @param host indirizzo ip del server
	 * @param port porta su cui e' in acolto il server
	 * 
	 * @throws IOException nel caso sorga qualche problema nella creazione del BufferIO
	 * @throws UnknownHostException nel caso sorga qualche problema nella risoluzione dell'host da raggiungere
	 */
	
	public SocketServer(String host, int port) throws UnknownHostException, IOException{
		super("SocketServer");
		this.host=host;
		this.port=port;
		
		this.bufferIO=new BufferIO(this.host, this.port);
		this.bufferIO.start();
		this.start();
	}
	
	/*
	 * (non-Javadoc)
	 * @see common.ServerInterface#inGame(int)
	 */
	@Override
	public void inGame(int token) throws InvalidTokenException,
			FullMatchException, RemoteException {
		String message="@"+this.comandList[4]+","+this.optionList[1]+"="+token;
		String comandName;
		
	
		message=readAndWrite(message);
		comandName=ComandParser.getName(message);
		
		if(comandName.equals("no")){
			comandName=ComandParser.parse(message, ",@(\\w{2,})", null)[0];
		if(ExceptionHandler.isException(comandName)){
			if (comandName.equalsIgnoreCase(ExceptionHandler.fromExceptionToComand(new InvalidTokenException())))
				throw new InvalidTokenException();
			if (comandName.equalsIgnoreCase(ExceptionHandler.fromExceptionToComand(new FullMatchException())))
				throw new InvalidTokenException();
			if (comandName.equalsIgnoreCase(ExceptionHandler.fromExceptionToComand(new IllegalArgumentException())))
				throw new IllegalArgumentException();
						
		}
		}
		
	}
	/*
	 * (non-Javadoc)
	 * @see common.ServerInterface#newSpecies(int, java.lang.String, char)
	 */
	@Override
	public void newSpecies(int token, String name, char type)
			throws InvalidTokenException, BusyNameException, RemoteException {
		
		String message="@"+this.comandList[3]+","+this.optionList[1]+"="+token+","+this.optionList[5]+"="+name+","+this.optionList[6]+"="+type;
		String comandName;
		
		
		message=readAndWrite(message);
		comandName=ComandParser.getName(message);
		
		if(comandName.equals("no")){
			comandName=ComandParser.parse(message, ",@(\\w{2,})", null)[0];
		if(ExceptionHandler.isException(comandName)){
			if (comandName.equalsIgnoreCase(ExceptionHandler.fromExceptionToComand(new InvalidTokenException())))
				throw new InvalidTokenException();
			if (comandName.equalsIgnoreCase(ExceptionHandler.fromExceptionToComand(new BusyNameException())))
				throw new BusyNameException();
		}
		}
		
	}
	/*
	 * (non-Javadoc)
	 * @see common.ServerInterface#newUser(java.lang.String, java.lang.String)
	 */
	@Override
	public void newUser(String username, String psw) throws BusyNameException,
			RemoteException {
		String message="@"+this.comandList[1]+","+this.optionList[3]+"="+username+","+this.optionList[4]+"="+psw;
		String comandName;
		
		message=readAndWrite(message);
		comandName=ComandParser.getName(message);
		
		if(comandName.equals("no")){
			comandName=ComandParser.parse(message, ",@(\\w{2,})", null)[0];
		if(ExceptionHandler.isException(comandName))
			throw new BusyNameException();
		}
				
	}

	/*
	 * (non-Javadoc)
	 * @see common.ServerInterface#growDino(int, int)
	 */
	@Override
	public void growDino(int token, int idDino) throws InvalidTokenException,
			 RemoteException, InvalidIdException, NotYourTurnException, MaxNumberOfDinoException, StarvedException, NotInMatchException, ExtinctionException {
		String message="@"+this.comandList[14]+","+this.optionList[1]+"="+token+","+this.optionList[2]+"="+idDino;
		String comandName;
		
		
		message=readAndWrite(message);
		comandName=ComandParser.getName(message);
		
		if(comandName.equals("no")){
			comandName=ComandParser.parse(message, ",@(\\w{2,})", null)[0];
		if(ExceptionHandler.isException(comandName)){
			if(comandName.equalsIgnoreCase(ExceptionHandler.fromExceptionToComand(new InvalidTokenException())))
				throw new InvalidTokenException();
			if(comandName.equalsIgnoreCase(ExceptionHandler.fromExceptionToComand(new NotYourTurnException())))
				throw new NotYourTurnException();
			if(comandName.equalsIgnoreCase(ExceptionHandler.fromExceptionToComand(new MaxNumberOfDinoException())))
				throw new MaxNumberOfDinoException();
			if(comandName.equalsIgnoreCase(ExceptionHandler.fromExceptionToComand(new InvalidIdException())))
				throw new InvalidIdException();
			if(comandName.equalsIgnoreCase(ExceptionHandler.fromExceptionToComand(new StarvedException())))
				throw new StarvedException();
			if(comandName.equalsIgnoreCase(ExceptionHandler.fromExceptionToComand(new NotInMatchException())))
				throw new NotInMatchException();
			if(comandName.equalsIgnoreCase(ExceptionHandler.fromExceptionToComand(new ExtinctionException())))
				throw new ExtinctionException();
		}
		}
		if(! comandName.equalsIgnoreCase("ok")){
			throw new RuntimeException("Unknown command: " + comandName);
			
		}		
	}

	/*
	 * (non-Javadoc)
	 * @see common.ServerInterface#egg(int, int)
	 */
	@Override
	public int egg(int token, int idDIno) throws InvalidTokenException,
			InvalidIdException, NotYourTurnException, MaxNumberOfDinoException, StarvedException, ExtinctionException, RemoteException, NotInMatchException {
		String message="@"+this.comandList[15]+","+this.optionList[1]+"="+token+","+this.optionList[2]+"="+idDIno;
		String comandName;
		int idNewDino=-1;
		
		message=readAndWrite(message);
		comandName=ComandParser.getName(message);
		
		if(comandName.equals("no")){
			comandName=ComandParser.parse(message, ",@(\\w{2,})", null)[0];
		if(ExceptionHandler.isException(comandName)){
			if(comandName.equalsIgnoreCase(ExceptionHandler.fromExceptionToComand(new InvalidTokenException())))
				throw new InvalidTokenException();
			if(comandName.equalsIgnoreCase(ExceptionHandler.fromExceptionToComand(new NotYourTurnException())))
				throw new NotYourTurnException();
			if(comandName.equalsIgnoreCase(ExceptionHandler.fromExceptionToComand(new MaxNumberOfDinoException())))
				throw new MaxNumberOfDinoException();
			if(comandName.equalsIgnoreCase(ExceptionHandler.fromExceptionToComand(new InvalidIdException())))
				throw new InvalidIdException();
			if(comandName.equalsIgnoreCase(ExceptionHandler.fromExceptionToComand(new StarvedException())))
				throw new StarvedException();
			if(comandName.equalsIgnoreCase(ExceptionHandler.fromExceptionToComand(new NotInMatchException())))
				throw new NotInMatchException();
			if(comandName.equalsIgnoreCase(ExceptionHandler.fromExceptionToComand(new ExtinctionException())))
				throw new ExtinctionException();
		}
		}
		if(comandName.equalsIgnoreCase("ok")){
			int [] groups={1};
			String [] stringidDino=ComandParser.parse(message, this.patternsServer[8], groups);
			idNewDino=Integer.valueOf(stringidDino[0]).intValue();
			
		}
		return idNewDino;
		
	}

	/*
	 * (non-Javadoc)
	 * @see common.ServerInterface#getRanking(int)
	 */
	@Override
	public Ranking getRanking(int token) throws InvalidTokenException,
			RemoteException {
		String message="@"+this.comandList[7]+","+this.optionList[1]+"="+token;
		String comandName;
		Ranking ranking=null;
		
		message=readAndWrite(message);
		comandName=ComandParser.getName(message);
		
		if(comandName.equals("no")){
			comandName=ComandParser.parse(message, ",@(\\w{2,})", null)[0];
		if(ExceptionHandler.isException(comandName))
				throw new InvalidTokenException();
		}
		
	  String option[]=ComandParser.parse(message, this.patternsServer[2], null);
	  ranking=Ranking.getRanking();
	  ArrayList<String> players = ranking.getPlayers();
	  for(int i=0; i< option.length/4;i++){
		int multy=i*4;
		if (! players.contains(option[0+multy]))
			ranking.putPlayer(Integer.valueOf(option[2+multy]).intValue(), option[0+multy], option[1+multy]);
		else
			ranking.updateScore(option[0+multy], Integer.valueOf(option[2+multy]).intValue());
		
		if(option[3+multy].equalsIgnoreCase("n"))
			ranking.setExtinct(option[0+multy]);
		else{
			ranking.setPlaying(option[0+multy]);
		}
		  
			
		}
		
		
		
	
		return ranking;
	}
	/*
	 * (non-Javadoc)
	 * @see common.ServerInterface#getPlayers(int)
	 */
	@Override
	public String[] getPlayers(int token) throws InvalidTokenException,
			RemoteException {
		String message="@"+this.comandList[6]+","+this.optionList[1]+"="+token;
		String comandName;
		String [] playerList=null;

		message=readAndWrite(message);
		comandName=ComandParser.getName(message);
		
		if(comandName.equals("no")){
			comandName=ComandParser.parse(message, ",@(\\w{2,})", null)[0];
		if(ExceptionHandler.isException(comandName))
				throw new InvalidTokenException();
		}
		if( !comandName.equalsIgnoreCase("no")){
			// se non ci sono giocatori in gioco ci si aspetta array vuoto
			int []groups={1};
			playerList=ComandParser.parse(message, this.patternsServer[1], groups);		
		}
		
		
		return playerList;
	}
	/*
	 * (non-Javadoc)
	 * @see common.ServerInterface#getDinoList(int)
	 */
	@Override
	public Integer[] getDinoList(int token) throws InvalidTokenException,
			NotInMatchException, RemoteException {
		String message="@"+this.comandList[10]+","+this.optionList[1]+"="+token;
		String comandName;
		Integer[] dinoList=null;
		
		message=readAndWrite(message);
		comandName=ComandParser.getName(message);
		
		if(comandName.equals("no")){
			comandName=ComandParser.parse(message, ",@(\\w{2,})", null)[0];
		if(ExceptionHandler.isException(comandName)){
			if (comandName.equalsIgnoreCase(ExceptionHandler.fromExceptionToComand(new InvalidTokenException())))
				throw new InvalidTokenException();
			if (comandName.equalsIgnoreCase(ExceptionHandler.fromExceptionToComand(new NotInMatchException())))
				throw new NotInMatchException();
			
		}	
		}
		int []groups={1};
		String [] stringDinoList=ComandParser.parse(message, this.patternsServer[8], groups);
		dinoList=new Integer[stringDinoList.length];
		for(int i=0;i<dinoList.length; i++){
			dinoList[i]=Integer.valueOf(stringDinoList[i]);
			
		}
		
		
		
		return dinoList;
	}
	/*
	 * (non-Javadoc)
	 * @see common.ServerInterface#getMap(int)
	 */
	@Override
	public UserMap getMap(int token) throws InvalidTokenException,
			NotInMatchException, RemoteException {
		String message="@"+this.comandList[9]+","+this.optionList[1]+"="+token;
		String comandName;
		UserMap userMap=null;
		//Costanti dell'origine della mappa, 0,0?
		int xOrigin=0;
		int yOrigin=0;

		message=readAndWrite(message);
		comandName=ComandParser.getName(message);
		
		if(comandName.equals("no")){
			comandName=ComandParser.parse(message, ",@(\\w{2,})", null)[0];
		if(ExceptionHandler.isException(comandName)){
			if (comandName.equalsIgnoreCase(ExceptionHandler.fromExceptionToComand(new InvalidTokenException())))
				throw new InvalidTokenException();
			if (comandName.equalsIgnoreCase(ExceptionHandler.fromExceptionToComand(new NotInMatchException())))
				throw new NotInMatchException();
			
		}	
		}
		//ottengo numero di righe e clonne
		int [] groupsRaC={1,2};
		String[] rowAndCulumn=ComandParser.parse(message, this.patternsServer[5], groupsRaC);
		//Creo la matrice di char per accogliere le caselle
		char [][] map=new char[Integer.valueOf(rowAndCulumn[0]).intValue()][Integer.valueOf(rowAndCulumn[1]).intValue()];
		//Ottengo la lista delle caselle.
		int [] groupsB={1};
		String [] box=ComandParser.parse(message, this.patternsServer[6], groupsB);
		//Costruisco la mappa di char;
		// corrispondenza elemento dell'array, con elemento matrice:
		// map[i][j]=box[j+(map.length*i)]
		// prengo il primo ed unico char presente
		for(int i=0; i< map.length;i++){
			for(int j=0; j<map[i].length;j++)
				map[i][j]=box[j+(map.length*i)].charAt(0);
						
		}
		UserMap.BoxType [][]boxes=new UserMap.BoxType [map.length][map[1].length];
		//Ma proca puttana 'c'era da cambiare il costruttore di UserMap?
		for(int i=0;i< boxes.length; i++)
			for(int j=0; j< boxes[i].length; j++){
				switch(map[i][j]){
					case 'a':
						boxes[i][j]=BoxType.WATER;
						break;
					case 't':
						boxes[i][j]=BoxType.LAND;
						break;
					case 'v':
						boxes[i][j]=BoxType.VEGE;
						break;
					case 'b':
						boxes[i][j]=BoxType.DARK;
						break;
					case 'd':
						boxes[i][j]=BoxType.DINO;
						break;
					case 'c':
						boxes[i][j]=BoxType.MEAT;
						break;
								
				}
				
				
			}
				
		
		
		userMap=new UserMap(Integer.valueOf(rowAndCulumn[0]).intValue(),xOrigin,yOrigin, boxes);
		
		
		return userMap;
				
				
				
	}
	/*
	 * (non-Javadoc)
	 * @see common.ServerInterface#getDinoStat(int, int)
	 */
	@Override
	public Vector getDinoStat(int token, int idDino)
			throws InvalidTokenException, InvalidIdException,
			NotInMatchException, RemoteException {
		
		String message="@"+this.comandList[12]+","+this.optionList[1]+"="+token+","+this.optionList[2]+"="+idDino;
		String comandName;
		Vector<Object> dinoStat=null;
				
		message=readAndWrite(message);
		comandName=ComandParser.getName(message);
		
		if(comandName.equals("no")){
			comandName=ComandParser.parse(message, ",@(\\w{2,})", null)[0];
		if(ExceptionHandler.isException(comandName)){
			if (comandName.equalsIgnoreCase(ExceptionHandler.fromExceptionToComand(new InvalidTokenException())))
				throw new InvalidTokenException();
			if (comandName.equalsIgnoreCase(ExceptionHandler.fromExceptionToComand(new InvalidIdException())))
				throw new InvalidIdException();
			if (comandName.equalsIgnoreCase(ExceptionHandler.fromExceptionToComand(new NotInMatchException())))
				throw new NotInMatchException();
					
		}	
		}
		int [] groups={1,2,3,4,5,6,7,8};
		String[] option=ComandParser.parse(message, this.patternsServer[3], groups);
		dinoStat=new Vector<Object>();
		/*Per ogni opzione nella lista,
		 * 	Se e' un numero, convettilo in int
		 * 	se e' una stringa lasciala stare
		 * Aggiungi l'oggetto all Vector.
		 * 
		 */
		int i=1;
		for(String str: option){
			if(i==3){
				dinoStat.add(str.charAt(0));
				i++;
				continue;
			}
			dinoStat.add(isInt(str) ?Integer.valueOf(str).intValue() : str);
			i++;
		}
	
		return dinoStat;
	}
	/*
	 * (non-Javadoc)
	 * @see common.ServerInterface#getDinoVisual(int, int)
	 */
	@Override
	public UserMap getDinoVisual(int token, int idDino)
			throws InvalidTokenException, InvalidIdException,
			NotInMatchException, RemoteException {
		
		String message="@"+this.comandList[11]+","+this.optionList[1]+"="+token+","+this.optionList[2]+"="+idDino;
		String comandName;
		UserMap userMap=null;

		
		message=readAndWrite(message);
		comandName=ComandParser.getName(message);
		
		if(comandName.equals("no")){
			comandName=ComandParser.parse(message, ",@(\\w{2,})", null)[0];
		if(ExceptionHandler.isException(comandName)){
			if (comandName.equalsIgnoreCase(ExceptionHandler.fromExceptionToComand(new InvalidTokenException())))
				throw new InvalidTokenException();
			if (comandName.equalsIgnoreCase(ExceptionHandler.fromExceptionToComand(new NotInMatchException())))
				throw new NotInMatchException();
			
		}	
		}
		//ottengo: Xorigin,Yorigin, numero di righe e clonne
		int [] groupsRaC={1,2};
		String[] option=ComandParser.parse(message, this.patternsServer[5], groupsRaC);
		int[] xAndYorigin={ Integer.valueOf(option[0]).intValue(),Integer.valueOf(option[1])};
		int[] rowAndCulumn={Integer.valueOf(option[2]),Integer.valueOf(option[3])};
		
		//Creo la matrice di char per accogliere le caselle
		//Ottengo la lista delle caselle.
		int [] groupsB={1};
		String [] box=ComandParser.parse(message, this.patternsServer[7], groupsB);
		//Mappe in cui memorizzare, valori di energia e valori delle caselle
		int [][] values=new int [rowAndCulumn[0]][rowAndCulumn[1]];
		BoxType [][]map=new BoxType [rowAndCulumn[0]][rowAndCulumn[0]];
		//Costruisco la mappa di Enum
		// map[i][j]=box[j+(map.length*i)]
		//uso la funzione interna isInt per determina se sia un numero o meno
		// prendo il primo ed unico char presente
		/*Inserisci(regole)
		 * se = a|t|num
		 * 	se e' numero
		 * 		inserisci int value
		 * 	se j==box.length-1
		 *		j=0
		 *		i++ 
		 *	altrimenti
		 *		j++
		 */
		
		int i=0;
		int j=0;
		for(String str: box){
			if(!str.isEmpty()){
				switch (str.toCharArray()[0]) {
				case 'a':
					map[i][j]=BoxType.WATER;
					break;
				case 't':
					map[i][j]=BoxType.LAND;
					break;
				case 'v':
					map[i][j]=BoxType.VEGE;
					break;
				case 'c':
					map[i][j]=BoxType.MEAT;
					break;	
				case 'b':
					map[i][j]=BoxType.DARK;
					break;
				case 'd':
					map[i][j]=BoxType.DINO;
					break;
				default:
					break;

				}
				if(str.equalsIgnoreCase("a")||str.equalsIgnoreCase("t")||str.equalsIgnoreCase("b")||str.equalsIgnoreCase("n")||isInt(str)){
					if(isInt(str))
						values[i][j]=Integer.valueOf(str).intValue();
					if(j==map.length-1){
						j=0;
						i++;
					}
					else{
						j++;
					}
				}
			}
		}
		
		userMap=new UserMap(map.length, xAndYorigin[0], xAndYorigin[1],map);
		userMap.setValues(values);
		return userMap;
	}

	/*
	 * (non-Javadoc)
	 * @see common.ServerInterface#login(java.lang.String, java.lang.String)
	 */
	@Override
	public int login(String username, String psw)
			throws FailedAuthenticationException, RemoteException {
		String message="@"+this.comandList[2]+","+this.optionList[3]+"="+username+","+this.optionList[4]+"="+psw;
		String comandName;
		String []optionList;
		int token=-1;
		
		message=readAndWrite(message);		
		comandName=ComandParser.getName(message);
		
		if(comandName.equals("no")){
			comandName=ComandParser.parse(message, ",@(\\w{2,})", null)[0];
		if(ExceptionHandler.isException(comandName))
				throw new FailedAuthenticationException();
		}
		if(comandName.equalsIgnoreCase("ok")){
			int []groups={1};
			optionList=ComandParser.parse(message, this.patternsServer[1], groups);
			token=Integer.valueOf(optionList[0]).intValue();
			
		}
		
		
		
		return token;
	}

	/*
	 * (non-Javadoc)
	 * @see common.ServerInterface#logout(int)
	 */
	@Override
	public void logout(int token) throws InvalidTokenException, RemoteException {
		String message="@"+this.comandList[8]+","+this.optionList[1]+"="+token;
		String comandName;
		
		message=readAndWrite(message);
		comandName=ComandParser.getName(message);
		
		if(comandName.equals("no")){
			comandName=ComandParser.parse(message, ",@(\\w{2,})", null)[0];
		if(ExceptionHandler.isException(comandName))
				throw new InvalidTokenException();
		}
		if(! comandName.equalsIgnoreCase("ok")){
			throw new RuntimeException("Unknown command: " + comandName);
			
		}
		
	}
	/*
	 * (non-Javadoc)
	 * @see common.ServerInterface#skipTurn(int)
	 */
	@Override
	public void skipTurn(int token) throws InvalidTokenException,
			NotInMatchException, RemoteException, NotYourTurnException {
		String message="@"+this.comandList[17]+","+this.optionList[1]+"="+token;
		String comandName;
		
		message=readAndWrite(message);
		comandName=ComandParser.getName(message);
		
		if(comandName.equals("no")){
			comandName=ComandParser.parse(message, ",@(\\w{2,})", null)[0];
		if(ExceptionHandler.isException(comandName)){
			if(comandName.equalsIgnoreCase(ExceptionHandler.fromExceptionToComand(new InvalidTokenException())))
				throw new InvalidTokenException();
			if(comandName.equalsIgnoreCase(ExceptionHandler.fromExceptionToComand(new NotInMatchException())))
				throw new NotInMatchException();
			if(comandName.equalsIgnoreCase(ExceptionHandler.fromExceptionToComand(new NotYourTurnException())))
				throw new NotYourTurnException();
			
		}
		}
		if(! comandName.equalsIgnoreCase("ok")){
			throw new RuntimeException("Unknown command: " + comandName);
			
		}
		
	}
	/*
	 * (non-Javadoc)
	 * @see common.ServerInterface#useTurn(int)
	 */
	@Override
	public void useTurn(int token) throws InvalidTokenException,
			NotInMatchException, NotYourTurnException, RemoteException {
		String message="@"+this.comandList[16]+","+this.optionList[1]+"="+token;
		String comandName;
		
		message=readAndWrite(message);
		comandName=ComandParser.getName(message);
		
		if(comandName.equals("no")){
			comandName=ComandParser.parse(message, ",@(\\w{2,})", null)[0];
		if(ExceptionHandler.isException(comandName)){
			if(comandName.equalsIgnoreCase(ExceptionHandler.fromExceptionToComand(new InvalidTokenException())))
				throw new InvalidTokenException();
			if(comandName.equalsIgnoreCase(ExceptionHandler.fromExceptionToComand(new NotInMatchException())))
				throw new NotInMatchException();
			if(comandName.equalsIgnoreCase(ExceptionHandler.fromExceptionToComand(new NotYourTurnException())))
				throw new NotYourTurnException();
			
		}
		}
		if(! comandName.equalsIgnoreCase("ok")){
			throw new RuntimeException("Unknown command: " + comandName);
			
		}
		
	}
	/*
	 * (non-Javadoc)
	 * @see common.ServerInterface#outGame(int)
	 */
	@Override
	public void outGame(int token) throws InvalidTokenException,
			RemoteException {
		String message="@"+this.comandList[5]+","+this.optionList[1]+"="+token;
		String comandName;
		
		message=readAndWrite(message);
		comandName=ComandParser.getName(message);
		
		if(comandName.equals("no")){
			comandName=ComandParser.parse(message, ",@(\\w{2,})", null)[0];
		if(ExceptionHandler.isException(comandName))
				throw new InvalidTokenException();
		}
		if(! comandName.equalsIgnoreCase("ok")){
			throw new RuntimeException("Unknown command: " + comandName);
			
		}
		
	}
	/*
	 * (non-Javadoc)
	 * @see common.ServerInterface#move(int, int, int[])
	 */
	@Override
	public char move(int token, int idDino, int[] destination)
			throws InvalidTokenException, InvalidIdException,
			NotInMatchException, GameException, RemoteException {
		
		return this.move(token, idDino, destination[0], destination[1]);
	}

	/*
	 * (non-Javadoc)
	 * @see common.TurnInterface#isChanged()
	 */

	@Override
	public boolean isChanged(){
		boolean tempIsChanged;
		synchronized (this.isChanged) {
			tempIsChanged=this.isChanged;
			this.isChanged=false;	
		}
		
		return tempIsChanged;
	
		
	}
	
	/*
	 * (non-Javadoc)
	 * @see common.TurnInterface#getPlayer()
	 */
	@Override
	public String getPlayer(){
						
		return 	this.playerName;
		
	}
	/*
	 * 
	 * finche' trovo una nuova stringa
	 * 	allora setta che il giocatore e' cambiato
	 * aspetta 10 secondi
	 */
	public void run(){
		while(true){
			updateTurn();
		try {
			sleep(5*1000);
		} catch (InterruptedException e) {e.printStackTrace();}
			
		}
	}
	
	
	private char move(int token, int idDino, int x, int y) throws InvalidTokenException, InvalidIdException,
	NotInMatchException, NotYourTurnException, MaxNumberOfDinoException, StarvedException, InvalidDestinationException, ExtinctionException {
		String message="@"+this.comandList[13]+","+this.optionList[1]+"="+token+","+this.optionList[2]+"="+idDino+","+this.optionList[7]+"={"+x+","+y+"}";
		String comandName;
		char result=0;

		message=readAndWrite(message);
		comandName=ComandParser.getName(message);
		
		if(comandName.equals("no")){
			comandName=ComandParser.parse(message, ",@(\\w{2,})", null)[0];
		if(ExceptionHandler.isException(comandName)){
			if(comandName.equalsIgnoreCase(ExceptionHandler.fromExceptionToComand(new InvalidTokenException())))
				throw new InvalidTokenException();
			if(comandName.equalsIgnoreCase(ExceptionHandler.fromExceptionToComand(new NotYourTurnException())))
				throw new NotYourTurnException();
			if(comandName.equalsIgnoreCase(ExceptionHandler.fromExceptionToComand(new MaxNumberOfDinoException())))
				throw new MaxNumberOfDinoException();
			if(comandName.equalsIgnoreCase(ExceptionHandler.fromExceptionToComand(new InvalidIdException())))
				throw new InvalidIdException();
			if(comandName.equalsIgnoreCase(ExceptionHandler.fromExceptionToComand(new StarvedException())))
				throw new StarvedException();
			if(comandName.equalsIgnoreCase(ExceptionHandler.fromExceptionToComand(new NotInMatchException())))
				throw new NotInMatchException();
			if(comandName.equalsIgnoreCase(ExceptionHandler.fromExceptionToComand(new InvalidDestinationException())))
				throw new InvalidDestinationException();
			if(comandName.equalsIgnoreCase(ExceptionHandler.fromExceptionToComand(new ExtinctionException())))
				throw new ExtinctionException();
		}
		}
		if(comandName.equalsIgnoreCase("ok")){
			//nessun combattimento
			result='x';

		}
		if(comandName.equalsIgnoreCase("combattimento")){
			int [] groups={1};
			String []optionList=ComandParser.parse(message, this.patternsServer[4], groups);
			char resultToTRanslate=optionList[0].charAt(0);
			//Se ha perso il combattimento, trasformo il messaggio dal server(p) in (n), valore di ritorno aspettato in questo caso;
			if(resultToTRanslate=='p')
				resultToTRanslate='n';

			result=resultToTRanslate;
		}


		return result;

	}
	
	
	private synchronized boolean updateTurn(){
		int index;
		boolean returnValue=false;
		while((index=this.bufferIO.find("cambioTurno"))!=-1){
			synchronized (this.playerName) {
				this.playerName=ComandParser.parse(this.bufferIO.messageAt(index), this.patternsServer[8],null)[0];
			}
			synchronized (this.isChanged) {
				this.isChanged=true;
				returnValue=true;
			}
			
		}	
		return returnValue;
		
				
	}

	private  boolean isInt(String str){

		try{Integer.parseInt(str);}
		catch(Exception e){
			return false;
		}
		return true;

	}
	
	private int write(String message){
		
		return this.bufferIO.write(message);
	
	}
	private String read(){
		
		String message=null;
		while(message==null){
			if(!this.bufferIO.isEmpty()){
				if(this.updateTurn())continue;
				
				message=this.bufferIO.read();
			}
		}
		return message;
		
	}

	private synchronized String readAndWrite(String message){
		write( message);
		return read();
		
	}
}


